
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

public class BankServer implements Server {
    /** Contains a map of Id's (integers) to banks */
    private Map<Integer,InternalBank> banks = new HashMap<Integer, InternalBank>();

    /** A bank which handles accounts */
    private class InternalBank{
        /** The map containing the integer to accounts linking */
        public Map<Integer, InternalAccount> accounts = new HashMap<Integer, InternalAccount>();
    }

    /** An account with a name and balance */
    private class InternalAccount{
        public String name;
        public double balance;
    }

    public void processFullGET(Socket socket, String URL) throws IOException {
        BufferedWriter toClient = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

        StringTokenizer tokenizer = new StringTokenizer(URL, "/");
        int amountOfTokens = tokenizer.countTokens();
        String format;

        //Check for minimum of tokens
        if(amountOfTokens >= 4){

            format = tokenizer.nextToken();
            if (!format.equals("BANK")) {
                System.out.println("BANKSERVER: missing BANK in format");
            } else {
                int bankID;

                try{
                    bankID = Integer.parseInt(tokenizer.nextToken()); //Should have BANK id

                    //Since we handle a number of banks, get or create the bank specified in the request
                    InternalBank bank = banks.get(bankID);
                    if(bank == null){
                        System.out.println("BANKSERVER: Creating new bank with ID: " + bankID);
                        bank = new InternalBank();
                        banks.put(bankID, bank);
                    }

                    //Is it a valid command?
                    format = tokenizer.nextToken();
                    if(format.equals("ACCOUNTLOOKUP") && amountOfTokens == 4){
                        accountLookupCmd(tokenizer.nextToken(), toClient, bank);
                    }
                    else if(format.equals("ACCOUNT") && amountOfTokens >= 5){
                        handleAccountCmd(tokenizer, bank, toClient, amountOfTokens);
                    }
                    else{
                        System.out.println("BANKSERVER: Not Account lookup or account request. Bad format.");
                    }
                }
                catch(NumberFormatException e){ //Error bad number format
                    System.out.println("BANKSERVER: couldn't parse integer");
                    System.out.println(e);
                }
            }
        }
        else{
            System.out.println("BANKSERVER: Not enough tokens");
        }

        toClient.flush();
        toClient.close();
    }

    private void handleAccountCmd(StringTokenizer tokenizer, InternalBank bank,
                                  BufferedWriter toClient, int amountOfTokens) throws IOException, NumberFormatException {
        int accountID = Integer.parseInt(tokenizer.nextToken()); //Should contain ACCOUNT id
        InternalAccount account = bank.accounts.get(accountID);
        if (account == null) {
            System.out.println("BANKSERVER-ACCOUNT: No account with that id.");
        } else {
            String format = tokenizer.nextToken();

            if(format.equals("BALANCE") && amountOfTokens == 5){
                double balance = account.balance;
                System.out.println("BANKSERVER-ACCOUNT: BALANCE, responding with the balance of the account.");
                toClient.write("HTTP/1.0 200 OK\n\n");
                toClient.write(balance + "\n");
            }
            else if(format.equals("NAME") && amountOfTokens == 5){
                String name = account.name;
                System.out.println("BANKSERVER-ACCOUNT: NAME, responding with the name of the account holder.");
                toClient.write("HTTP/1.0 200 OK\n\n");
                toClient.write(name + "\n");
            }
            else if(format.equals("DEPOSIT") && amountOfTokens == 6){
                double amount = Double.parseDouble(tokenizer.nextToken());
                System.out.println("BANKSERVER-ACCOUNT: DEPOSIT " + amount);
                account.balance = account.balance + amount;
            }
            else if(format.equals("WITHDRAW") && amountOfTokens == 6){
                double amount = Double.parseDouble(tokenizer.nextToken());
                System.out.println("BANKSERVER-ACCOUNT: WITHDRAW " + amount);
                account.balance = account.balance - amount;
            }
            else{
                System.out.println("BANKSERVER-ACCOUNT: Bad format, not BALANCE/WITHDRAW/DEPOSIT/NAME");
            }
        }
    }

    private void accountLookupCmd(String accountName, BufferedWriter toClient, InternalBank bank) throws IOException {
        System.out.println("BANKSERVER: Performing account lookup");
        InternalAccount account;

        //In the bank, run through every account until the correct one is found
        for(Integer i : bank.accounts.keySet()){

            account = bank.accounts.get(i);
            if(account == null){
                System.out.println("BANKSERVER-ACCLOOKUP: Null account found"); //shouldn't happen...
            }
            else{
                if(account.name.equals(accountName)){
                    System.out.println("BANKSERVER-ACCLOOKUP: Account found! ID: " + i);
                    toClient.write("HTTP/1.0 200 OK\n\n");
                    toClient.write(i + "\n");
                    return;
                }
            }
        }

        //No account has been found
        //Create new account with the name, put it in the current bank.
        account = new InternalAccount(); //the new account
        account.balance = 0;
        account.name = accountName;

        int accountID = bank.accounts.keySet().size() +1;
        bank.accounts.put(accountID, account);

        System.out.println("BANKSERVER-ACCLOOKUP: Account not found! Creating new. ID: " + accountID);
        toClient.write("HTTP/1.0 200 OK\n\n");
        toClient.write(accountID + "\n");
    }

    public void processSimpleGET(Socket socket, String URL) throws IOException {
        throw new UnsupportedOperationException();

    }

    public void processPUT(Socket socket, String URL) throws IOException {
        throw new UnsupportedOperationException();
    }

    public void processPOST(Socket socket, String URL) throws IOException {
        throw new UnsupportedOperationException();
    }
}
